﻿using System;

namespace SBValidation
{
    /// <summary>
    /// Provides validation methods.
    /// </summary>
    public static class ValidationConditions
    {
        /// <summary>
        /// The first method to start validation.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="value">The value to validate.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> Is<T>(this T value)
        {
            return new Validation<T>(value);
        }

        /// <summary>
        /// Checks wether value to validate is null.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> Null<T>(this Validation<T> validation)
            where T : class
        {
            validation.IsValid = validation.Value == null;

            return validation;
        }

        /// <summary>
        /// Checks wether value to validate is not null.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> NotNull<T>(this Validation<T> validation)
            where T : class
        {
            validation.IsValid = validation.Value != null;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is empty.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> Empty<T>(this Validation<T> validation)
        {
            validation.IsValid = validation.Value.ToString().Trim().Length == 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is not empty.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> NotEmpty<T>(this Validation<T> validation)
        {
            validation.IsValid = validation.Value.ToString().Trim().Length > 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is not null or empty.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> NotNullOrEmpty<T>(this Validation<T> validation)
            where T : class
        {
            validation.IsValid = validation.Value != null &&
                                 validation.Value.ToString().Trim().Length > 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is not equal to <paramref name="value"/>.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="value">The value to compare.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> NotEqual<T>(this Validation<T> validation, T value)
            where T : IEquatable<T>
        {
            validation.IsValid = !validation.Value.Equals(value);

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is greater the than <paramref name="value"/>.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="value">The value ti compare.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> GreaterThan<T>(this Validation<T> validation, T value)
            where T : IComparable<T>
        {
            validation.IsValid = validation.Value.CompareTo(value) > 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is greater the than or equal to <paramref name="value"/>.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="value">The value to compare.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> GreaterThanOrEqual<T>(this Validation<T> validation, T value)
            where T : IComparable<T>
        {
            validation.IsValid = validation.Value.CompareTo(value) >= 0;

            return validation;
        }

        /// <summary>
        /// Cheks whether value to validate is less than <paramref name="value"/>.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="value">The value to compare.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> LessThan<T>(this Validation<T> validation, T value)
            where T : IComparable<T>
        {
            validation.IsValid = validation.Value.CompareTo(value) < 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is less the than or equal to <paramref name="value"/>.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="value">The value to compare.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> LessThanOrEqual<T>(this Validation<T> validation, T value)
            where T : IComparable<T>
        {
            validation.IsValid = validation.Value.CompareTo(value) <= 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is in specified range inclusive.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="from">Range from.</param>
        /// <param name="to">Range to.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> InRange<T>(this Validation<T> validation, T from, T to)
            where T : IComparable<T>
        {
            validation.IsValid = validation.Value.CompareTo(from) >= 0 &&
                                 validation.Value.CompareTo(to) <= 0;

            return validation;
        }

        /// <summary>
        /// Checks whether value to validate is in specified range exclusive.
        /// </summary>
        /// <typeparam name="T">Type to validate.</typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="from">Range from.</param>
        /// <param name="to">Range to.</param>
        /// <returns>Validation class for fluent interface.</returns>
        public static Validation<T> InRangeExclusive<T>(this Validation<T> validation, T from, T to)
            where T : IComparable<T>
        {
            validation.IsValid = validation.Value.CompareTo(from) > 0 &&
                                 validation.Value.CompareTo(to) < 0;

            return validation;
        }
    }
}